import {Component} from 'react'
import Taro, {createSelectorQuery} from '@tarojs/taro'
import {View, Button, Canvas, Image} from '@tarojs/components'
import './index.scss'

// 导入markdown-it
import MarkdownIt from 'markdown-it'

const md = new MarkdownIt()

export default class Preview extends Component {
  constructor(props) {
    super(props)
    this.state = {
      markdown: '',
      canvasId: 'markdown-canvas',
      imageUrl: '',
      canvasWidth: 300,
      canvasHeight: 500
    }
  }

  componentDidMount() {
    // 从存储中获取markdown内容
    const markdown = Taro.getStorageSync('markdownContent') || ''
    this.setState({markdown}, () => {
      // 自动开始生成图片
      this.generateImage()
    })
  }

  // 生成图片
  generateImage = async () => {
    try {
      Taro.showLoading({title: '生成中...'})

      // 获取设备信息
      const systemInfo = Taro.getSystemInfoSync()
      const pixelRatio = systemInfo.pixelRatio || 2
      const windowWidth = systemInfo.windowWidth

      // 设置内容宽度为窗口宽度减去边距
      const contentWidth = windowWidth - 40

      // 估算高度 - 增加系数确保足够空间
      const {markdown} = this.state
      let estimatedHeight = this.estimateMarkdownHeight(markdown, contentWidth)

      // 确保有足够的空间
      estimatedHeight = Math.max(estimatedHeight, 800) // 至少800px高度

      // 设置Canvas尺寸
      const canvasWidth = contentWidth
      const canvasHeight = estimatedHeight

      this.setState({
        canvasWidth,
        canvasHeight
      }, async () => {
        // 使用Canvas绘制Markdown内容
        const canvas = await new Promise(resolve => {
          const q = createSelectorQuery()
          q.select(`#${this.state.canvasId}`).fields({node: true, size: true}).exec(res => {
            resolve(res[0].node)
          })
        })

        // 设置canvas实际尺寸（物理像素）
        canvas.width = canvasWidth * pixelRatio
        canvas.height = canvasHeight * pixelRatio

        const ctx = canvas.getContext('2d')

        // 缩放画布上下文，处理高清屏幕
        ctx.scale(pixelRatio, pixelRatio)

        // 绘制背景
        ctx.fillStyle = '#ffffff'
        ctx.fillRect(0, 0, canvasWidth, canvasHeight)

        // 渲染Markdown
        this.renderMarkdown(ctx, markdown, 20, 20, contentWidth - 40)

        // 转为临时文件路径
        const tempFilePath = await new Promise((resolve, reject) => {
          Taro.canvasToTempFilePath({
            canvas: canvas,
            success: (res) => {
              resolve(res.tempFilePath)
            },
            fail: (err) => {
              reject(err)
            }
          })
        })

        this.setState({
          imageUrl: tempFilePath
        })

        Taro.hideLoading()
      })
    } catch (error) {
      console.error('生成图片失败', error)
      Taro.hideLoading()
      Taro.showToast({
        title: '生成图片失败',
        icon: 'none'
      })
    }
  }

  // 完全重写的高度估算函数
  estimateMarkdownHeight = (markdown, width) => {
    const baseFontSize = 16
    const headingSizes = {
      h1: 24,
      h2: 22,
      h3: 20,
      h4: 18,
      h5: 16,
      h6: 16
    }
    const lineHeight = 1.5

    // 解析markdown获取tokens
    const tokens = md.parse(markdown, {})

    let totalHeight = 40 // 初始上下边距
    let listLevel = 0
    let codeBlockActive = false // 重命名变量

    for (let i = 0; i < tokens.length; i++) {
      const token = tokens[i]

      switch (token.type) {
        case 'heading_open':
          const level = parseInt(token.tag.slice(1))
          i++ // 移动到内容token

          if (tokens[i] && tokens[i].type === 'inline') {
            const text = tokens[i].content
            const fontSize = headingSizes[`h${level}`]

            // 估算标题所需行数
            const lines = this.estimateLines(text, width, fontSize)
            totalHeight += lines * fontSize * lineHeight + 20 // 标题行高加上间距
          }
          break

        case 'paragraph_open':
          i++ // 移动到内容token

          if (tokens[i] && tokens[i].type === 'inline') {
            const text = tokens[i].content

            // 移除markdown格式符号进行计算
            const cleanText = text
              .replace(/\*\*(.*?)\*\*/g, '$1')
              .replace(/\*(.*?)\*/g, '$1')
              .replace(/~~(.*?)~~/g, '$1')
              .replace(/`(.*?)`/g, '$1')
              .replace(/\[(.*?)\]\(.*?\)/g, '$1')

            // 估算段落所需行数
            const lines = this.estimateLines(cleanText, width, baseFontSize)
            totalHeight += lines * baseFontSize * lineHeight + 15 // 段落行高加上间距
          }
          break

        case 'bullet_list_open':
        case 'ordered_list_open':
          listLevel++
          totalHeight += 5 // 列表开始前的间距
          break

        case 'bullet_list_close':
        case 'ordered_list_close':
          listLevel--
          totalHeight += 5 // 列表结束后的间距
          break

        case 'list_item_open':
          i++ // 移动到内容token

          // 查找列表项内容
          while (i < tokens.length && tokens[i].type !== 'paragraph_open' && tokens[i].type !== 'list_item_close') {
            i++
          }

          if (i < tokens.length && tokens[i].type === 'paragraph_open') {
            i++ // 移动到段落内容

            if (tokens[i] && tokens[i].type === 'inline') {
              const text = tokens[i].content
              const cleanText = text
                .replace(/\*\*(.*?)\*\*/g, '$1')
                .replace(/\*(.*?)\*/g, '$1')
                .replace(/~~(.*?)~~/g, '$1')
                .replace(/`(.*?)`/g, '$1')
                .replace(/\[(.*?)\]\(.*?\)/g, '$1')

              // 列表项缩进
              const indent = 20 * listLevel
              // 估算列表项所需行数
              const lines = this.estimateLines(cleanText, width - indent, baseFontSize)
              totalHeight += lines * baseFontSize * lineHeight + 8 // 列表项行高加上间距
            }
          }
          break

        case 'fence':
        case 'code_block':
          codeBlockActive = true
          const codeLines = token.content.split('\n')
          // 代码块高度计算
          totalHeight += 15 // 代码块前的间距
          totalHeight += codeLines.length * baseFontSize * lineHeight + 10 // 代码行加上间距
          totalHeight += 15 // 代码块后的间距
          codeBlockActive = false
          break

        case 'hr':
          totalHeight += 30 // 水平线前后间距
          break

        case 'blockquote_open':
          totalHeight += 10 // 引用块前的间距
          break

        case 'blockquote_close':
          totalHeight += 10 // 引用块后的间距
          break
      }
    }

    // 确保足够的底部空间
    totalHeight += 40

    // 增加额外的空间，确保内容不会被截断
    totalHeight += 200; // 添加额外的200px空间确保内容完整显示

    return totalHeight
  }

  // 估算行数
  estimateLines = (text, width, fontSize) => {
    // 平均字符宽度估计值
    const avgCharWidth = fontSize * 0.6

    // 估算一行可容纳的字符数
    const charsPerLine = Math.floor(width / avgCharWidth)

    // 估算行数
    return Math.max(1, Math.ceil(text.length / charsPerLine))
  }

  // 渲染markdown到canvas
  renderMarkdown = (ctx, markdown, x, y, maxWidth) => {
    // 基础样式设置
    const baseFontSize = 16
    const headingSizes = {
      h1: 24,
      h2: 22,
      h3: 20,
      h4: 18,
      h5: 16,
      h6: 16
    }

    // 解析markdown获取tokens
    const tokens = md.parse(markdown, {})

    let currentY = y
    let listLevel = 0
    let listCounter = {} // 记录每级有序列表的计数

    // 处理tokens
    for (let i = 0; i < tokens.length; i++) {
      const token = tokens[i]

      switch (token.type) {
        case 'heading_open': {
          const level = parseInt(token.tag.slice(1))
          const fontSize = headingSizes[`h${level}`]

          i++ // 移动到内容token

          if (tokens[i] && tokens[i].type === 'inline') {
            const text = tokens[i].content

            // 增加标题前的间距
            currentY += 15

            // 设置标题字体
            ctx.font = `bold ${fontSize}px sans-serif`
            ctx.fillStyle = '#333333'

            // 处理标题文本
            currentY = this.renderWrappedText(ctx, text, x, currentY, maxWidth, fontSize, true)

            // 增加标题后的间距
            currentY += 5
          }
          break
        }

        case 'paragraph_open': {
          i++ // 移动到内容token

          if (tokens[i] && tokens[i].type === 'inline') {
            const text = tokens[i].content

            // 增加段落前的间距
            currentY += 10

            // 解析段落中的样式
            const segments = this.parseTextSegments(text)

            // 渲染格式化的段落
            currentY = this.renderFormattedParagraph(ctx, segments, x, currentY, maxWidth)

            // 增加段落后的间距
            currentY += 10
          }
          break
        }

        case 'bullet_list_open': {
          listLevel++
          // 列表前的间距
          currentY += 5
          break
        }

        case 'ordered_list_open': {
          listLevel++
          // 初始化这一级别的列表计数
          listCounter[listLevel] = 1
          // 列表前的间距
          currentY += 5
          break
        }

        case 'bullet_list_close':
        case 'ordered_list_close': {
          listLevel--
          // 列表后的间距
          currentY += 5
          // 如果关闭了有序列表，删除对应计数器
          if (token.type === 'ordered_list_close') {
            delete listCounter[listLevel + 1]
          }
          break
        }

        case 'list_item_open': {
          const bulletType = tokens[i - 1].type === 'bullet_list_open' || tokens[i - 1].type === 'list_item_close' && tokens[i - 2].type !== 'ordered_list_close' ? 'bullet' : 'ordered'

          const itemIndent = 20 * listLevel
          const bulletX = x + itemIndent - 15

          // 查找列表项内容
          let itemContent = ''
          let textSegments = []
          let j = i + 1

          while (j < tokens.length && tokens[j].type !== 'paragraph_open' && tokens[j].type !== 'list_item_close') {
            j++
          }

          if (j < tokens.length && tokens[j].type === 'paragraph_open') {
            j++
            if (j < tokens.length && tokens[j].type === 'inline') {
              itemContent = tokens[j].content
              textSegments = this.parseTextSegments(itemContent)
            }
          }

          // 设置字体
          ctx.font = `${baseFontSize}px sans-serif`
          ctx.fillStyle = '#333333'

          // 绘制圆点或序号
          if (bulletType === 'bullet') {
            ctx.beginPath()
            ctx.arc(bulletX, currentY + baseFontSize / 2 - 1, 3, 0, 2 * Math.PI)
            ctx.fill()
          } else {
            // 获取当前级别的计数
            const counter = listCounter[listLevel]
            ctx.fillText(`${counter}.`, bulletX - 5, currentY + baseFontSize)
            // 递增计数
            listCounter[listLevel]++
          }

          // 渲染列表项内容
          currentY = this.renderFormattedParagraph(ctx, textSegments, x + itemIndent, currentY, maxWidth - itemIndent)

          // 找到对应的list_item_close
          while (i < tokens.length && tokens[i].type !== 'list_item_close') {
            i++
          }

          break
        }

        case 'fence':
        case 'code_block': {
          const codeContent = token.content

          // 代码块前的间距
          currentY += 15

          // 设置代码字体
          ctx.font = '14px monospace'

          // 绘制代码块背景
          const codeLines = this.wrapCodeText(ctx, codeContent, maxWidth - 10)
          const codeHeight = codeLines.length * baseFontSize * 1.5 + 20

          ctx.fillStyle = '#f6f8fa'
          ctx.fillRect(x, currentY, maxWidth, codeHeight)

          // 绘制代码内容
          ctx.fillStyle = '#333333'
          let lineY = currentY + 15

          for (const line of codeLines) {
            ctx.fillText(line, x + 10, lineY)
            lineY += baseFontSize * 1.5
          }

          // 更新当前Y位置
          currentY += codeHeight

          // 代码块后的间距
          currentY += 15

          break
        }

        case 'hr': {
          // 水平线前的间距
          currentY += 15

          // 绘制水平线
          ctx.strokeStyle = '#dddddd'
          ctx.beginPath()
          ctx.moveTo(x, currentY)
          ctx.lineTo(x + maxWidth, currentY)
          ctx.stroke()

          // 水平线后的间距
          currentY += 15

          break
        }

        case 'blockquote_open': {
          // 引用块前的间距
          currentY += 10

          // 查找引用块内容
          let quoteContent = ''
          let j = i + 1

          while (j < tokens.length && tokens[j].type !== 'paragraph_open' && tokens[j].type !== 'blockquote_close') {
            j++
          }

          if (j < tokens.length && tokens[j].type === 'paragraph_open') {
            j++
            if (j < tokens.length && tokens[j].type === 'inline') {
              quoteContent = tokens[j].content
            }
          }

          // 解析引用内的样式
          const segments = this.parseTextSegments(quoteContent)

          // 绘制引用块背景
          const quoteHeight = this.estimateFormattedParagraphHeight(ctx, segments, maxWidth - 20)

          ctx.fillStyle = '#f5f5f5'
          ctx.fillRect(x, currentY, maxWidth, quoteHeight + 20)

          // 绘制左侧竖线
          ctx.fillStyle = '#dddddd'
          ctx.fillRect(x + 3, currentY, 3, quoteHeight + 20)

          // 渲染引用块内容
          ctx.fillStyle = '#666666'
          currentY = this.renderFormattedParagraph(ctx, segments, x + 15, currentY + 10, maxWidth - 25)

          // 引用块后的间距
          currentY += 10

          // 找到对应的blockquote_close
          while (i < tokens.length && tokens[i].type !== 'blockquote_close') {
            i++
          }

          break
        }
      }
    }

    return currentY
  }

  // 估算格式化段落高度
  estimateFormattedParagraphHeight = (ctx, segments, maxWidth) => {
    const fontSize = 16
    const lineHeight = fontSize * 1.5
    let totalHeight = 0
    let currentLineWidth = 0
    let lineCount = 1

    for (const segment of segments) {
      // 设置合适的字体
      if (segment.bold && segment.italic) {
        ctx.font = `bold italic ${fontSize}px sans-serif`
      } else if (segment.bold) {
        ctx.font = `bold ${fontSize}px sans-serif`
      } else if (segment.italic) {
        ctx.font = `italic ${fontSize}px sans-serif`
      } else if (segment.code) {
        ctx.font = `${fontSize}px monospace`
      } else {
        ctx.font = `${fontSize}px sans-serif`
      }

      // 分词处理
      const words = this.splitIntoWords(segment.text)

      for (const word of words) {
        const wordWidth = ctx.measureText(word).width

        if (currentLineWidth + wordWidth > maxWidth) {
          // 需要换行
          lineCount++
          currentLineWidth = wordWidth
        } else {
          // 继续当前行
          currentLineWidth += wordWidth
        }
      }
    }

    totalHeight = lineCount * lineHeight
    return totalHeight
  }

  // 渲染格式化的段落
  renderFormattedParagraph = (ctx, segments, x, y, maxWidth) => {
    const fontSize = 16
    const lineHeight = fontSize * 1.5
    let currentY = y
    let currentLineWidth = 0

    // 当前行的分段
    let currentLineSegments = []

    for (const segment of segments) {
      // 设置合适的字体
      if (segment.bold && segment.italic) {
        ctx.font = `bold italic ${fontSize}px sans-serif`
      } else if (segment.bold) {
        ctx.font = `bold ${fontSize}px sans-serif`
      } else if (segment.italic) {
        ctx.font = `italic ${fontSize}px sans-serif`
      } else if (segment.code) {
        ctx.font = `${fontSize}px monospace`
      } else {
        ctx.font = `${fontSize}px sans-serif`
      }

      // 分词处理
      const words = this.splitIntoWords(segment.text)

      for (const word of words) {
        const wordWidth = ctx.measureText(word).width

        if (currentLineWidth + wordWidth > maxWidth) {
          // 绘制当前行
          this.drawFormattedLine(ctx, currentLineSegments, x, currentY + fontSize)

          // 重置行数据
          currentLineSegments = []
          currentLineWidth = 0
          currentY += lineHeight

          // 添加当前单词到新行
          currentLineSegments.push({
            text: word,
            ...segment
          })
          currentLineWidth = wordWidth
        } else {
          // 添加到当前行
          currentLineSegments.push({
            text: word,
            ...segment
          })
          currentLineWidth += wordWidth
        }
      }
    }

    // 绘制最后一行
    if (currentLineSegments.length > 0) {
      this.drawFormattedLine(ctx, currentLineSegments, x, currentY + fontSize)
      currentY += lineHeight
    }

    return currentY
  }

  // 绘制格式化的单行
  drawFormattedLine = (ctx, segments, x, y) => {
    let currentX = x

    for (const segment of segments) {
      // 设置合适的字体
      const fontSize = 16

      if (segment.bold && segment.italic) {
        ctx.font = `bold italic ${fontSize}px sans-serif`
      } else if (segment.bold) {
        ctx.font = `bold ${fontSize}px sans-serif`
      } else if (segment.italic) {
        ctx.font = `italic ${fontSize}px sans-serif`
      } else if (segment.code) {
        ctx.font = `${fontSize}px monospace`
        // 代码段背景
        const codeWidth = ctx.measureText(segment.text).width
        ctx.fillStyle = '#f6f8fa'
        ctx.fillRect(currentX - 2, y - fontSize, codeWidth + 4, fontSize + 4)
      } else {
        ctx.font = `${fontSize}px sans-serif`
      }

      // 绘制文本
      ctx.fillStyle = '#333333'
      ctx.fillText(segment.text, currentX, y)

      // 更新X位置
      currentX += ctx.measureText(segment.text).width
    }
  }

  // 解析文本段落中的样式
  parseTextSegments = (text) => {
    const segments = []
    let pos = 0

    while (pos < text.length) {
      // 检查粗体+斜体
      if (pos + 3 < text.length &&
        text.substr(pos, 3) === '***' &&
        text.indexOf('***', pos + 3) !== -1) {
        const endPos = text.indexOf('***', pos + 3)
        const boldItalicText = text.substring(pos + 3, endPos)

        segments.push({
          text: boldItalicText,
          bold: true,
          italic: true,
          code: false
        })

        pos = endPos + 3
      }
      // 检查粗体
      else if (pos + 2 < text.length &&
        text.substr(pos, 2) === '**' &&
        text.indexOf('**', pos + 2) !== -1) {
        const endPos = text.indexOf('**', pos + 2)
        const boldText = text.substring(pos + 2, endPos)

        segments.push({
          text: boldText,
          bold: true,
          italic: false,
          code: false
        })

        pos = endPos + 2
      }
      // 检查斜体
      else if (pos + 1 < text.length &&
        text[pos] === '*' &&
        text.indexOf('*', pos + 1) !== -1 &&
        text[pos + 1] !== '*') {
        const endPos = text.indexOf('*', pos + 1)
        const italicText = text.substring(pos + 1, endPos)

        segments.push({
          text: italicText,
          bold: false,
          italic: true,
          code: false
        })

        pos = endPos + 1
      }
      // 检查行内代码
      else if (pos + 1 < text.length &&
        text[pos] === '`' &&
        text.indexOf('`', pos + 1) !== -1) {
        const endPos = text.indexOf('`', pos + 1)
        const codeText = text.substring(pos + 1, endPos)

        segments.push({
          text: codeText,
          bold: false,
          italic: false,
          code: true
        })

        pos = endPos + 1
      }
      // 普通文本
      else {
        // 寻找下一个格式标记
        let endPos = text.length

        const nextBold = text.indexOf('**', pos)
        const nextItalic = text.indexOf('*', pos)
        const nextCode = text.indexOf('`', pos)

        if (nextBold !== -1 && (endPos === text.length || nextBold < endPos)) endPos = nextBold
        if (nextItalic !== -1 && (endPos === text.length || nextItalic < endPos)) endPos = nextItalic
        if (nextCode !== -1 && (endPos === text.length || nextCode < endPos)) endPos = nextCode

        segments.push({
          text: text.substring(pos, endPos),
          bold: false,
          italic: false,
          code: false
        })

        pos = endPos
      }
    }

    return segments
  }

  // 拆分文本为单词
  splitIntoWords = (text) => {
    const words = []
    let currentWord = ''

    for (let i = 0; i < text.length; i++) {
      const char = text.charAt(i)

      // 中文字符单独处理
      if (/[\u4e00-\u9fa5]/.test(char)) {
        if (currentWord) {
          words.push(currentWord)
          currentWord = ''
        }
        words.push(char)
      }
      // 空格单独处理
      else if (char === ' ') {
        if (currentWord) {
          words.push(currentWord)
          currentWord = ''
        }
        words.push(' ')
      }
      // 英文和其他字符
      else {
        currentWord += char
      }
    }

    // 添加最后一个单词
    if (currentWord) {
      words.push(currentWord)
    }

    return words
  }

  // 处理普通文本换行
  renderWrappedText = (ctx, text, x, y, maxWidth, fontSize = 16, isBold = false) => {
    // 设置字体
    ctx.font = isBold ?
      `bold ${fontSize}px sans-serif` :
      `${fontSize}px sans-serif`

    // 清除格式标记
    const plainText = text
      .replace(/\*\*(.*?)\*\*/g, '$1')
      .replace(/\*(.*?)\*/g, '$1')
      .replace(/`(.*?)`/g, '$1')

    // 拆分文本为词
    const words = this.splitIntoWords(plainText)
    const lineHeight = fontSize * 1.5

    let currentLine = ''
    let currentY = y

    for (const word of words) {
      const testLine = currentLine + word
      const metrics = ctx.measureText(testLine)

      if (metrics.width > maxWidth && currentLine) {
        ctx.fillText(currentLine, x, currentY)
        currentY += lineHeight
        currentLine = word
      } else {
        currentLine = testLine
      }
    }

    // 绘制最后一行
    if (currentLine) {
      ctx.fillText(currentLine, x, currentY)
      currentY += lineHeight
    }

    return currentY
  }

  // 处理代码文本换行
  wrapCodeText = (ctx, code, maxWidth) => {
    const wrappedLines = []

    // 按行分割代码
    const codeLines = code.split('\n')

    for (const line of codeLines) {
      if (!line.trim()) {
        wrappedLines.push('')
        continue
      }

      let currentLine = ''

      // 设置monospace字体
      ctx.font = '14px monospace'

      for (let i = 0; i < line.length; i++) {
        const char = line.charAt(i)
        const testLine = currentLine + char
        const metrics = ctx.measureText(testLine)

        if (metrics.width > maxWidth && currentLine) {
          wrappedLines.push(currentLine)
          currentLine = char
        } else {
          currentLine = testLine
        }
      }

      // 添加最后一行
      if (currentLine) {
        wrappedLines.push(currentLine)
      }
    }

    // 如果没有内容，添加一个空行
    if (wrappedLines.length === 0) {
      wrappedLines.push('')
    }

    return wrappedLines
  }

  // 返回编辑页
  goBack = () => {
    Taro.navigateBack()
  }

  // 保存图片 - 添加权限校验
  saveImage = () => {
    const {imageUrl} = this.state
    if (!imageUrl) {
      Taro.showToast({
        title: '图片生成中，请稍候',
        icon: 'none'
      })
      return
    }

    // 获取用户授权状态
    Taro.getSetting({
      success: (res) => {
        // 如果没有授权写入相册的权限
        if (!res.authSetting['scope.writePhotosAlbum']) {
          Taro.authorize({
            scope: 'scope.writePhotosAlbum',
            success: () => {
              // 用户同意授权，保存图片
              this.saveImageToAlbum(imageUrl)
            },
            fail: () => {
              // 用户拒绝授权，引导用户开启权限
              Taro.showModal({
                title: '提示',
                content: '需要您授权保存图片到相册',
                confirmText: '前往授权',
                cancelText: '取消',
                success: (modalRes) => {
                  if (modalRes.confirm) {
                    Taro.openSetting()
                  }
                }
              })
            }
          })
        } else {
          // 已有权限，直接保存
          this.saveImageToAlbum(imageUrl)
        }
      },
      fail: () => {
        Taro.showToast({
          title: '获取授权状态失败',
          icon: 'none'
        })
      }
    })
  }

  // 实际保存图片到相册的方法
  saveImageToAlbum = (filePath) => {
    Taro.saveImageToPhotosAlbum({
      filePath: filePath,
      success: () => {
        Taro.showToast({
          title: '保存成功',
          icon: 'success'
        })
      },
      fail: (err) => {
        console.error('保存失败', err)
        Taro.showToast({
          title: '保存失败',
          icon: 'none'
        })
      }
    })
  }

  render() {
    const {imageUrl, canvasWidth, canvasHeight, canvasId} = this.state

    return (
      <View className='preview'>
        <View className='header'>
          <View className='title'>预览图片</View>
        </View>

        <View className='image-preview'>
          {imageUrl ? (
            <Image src={imageUrl} mode='widthFix'/>
          ) : (
            <View className='loading-message'>正在生成图片，请稍候...</View>
          )}
        </View>

        <View className='action-buttons'>
          <Button className='btn back-btn' onClick={this.goBack}>返回编辑</Button>
          <Button className='btn save-btn' onClick={this.saveImage}>保存到相册</Button>
        </View>

        <Canvas
          type='2d'
          id={canvasId}
          className='hidden-canvas'
          width={canvasWidth}
          height={canvasHeight}
        />
      </View>
    )
  }
}
